import { spawn } from 'child_process'
import * as path from 'path'

// ================== 配置 ==================
const PM2_APP_NAME = 'douxian-back'
const REMOTE = {
  user: 'root',
  host: '8.134.250.251',
  port: 22,
  path: `/data/nginx/${PM2_APP_NAME}`,
} as const
const FILES_TO_UPLOAD = ['dist', 'package.json', '.env.test'] as const
const LOCAL_PROJECT_PATH = path.resolve(__dirname, '../')
// =========================================

const buildCommandArgs = ['npm', 'run', 'build']
const sshPath = `${REMOTE.user}@${REMOTE.host}`

function runCommand(commandArgs: string[], options = {}) {
  return new Promise<void>((resolve, reject) => {
    const [command, ...args] = commandArgs
    // 需要显示输出日志切换为 inherit，打包速度会降低一倍
    const child = spawn(command, args, {
      // stdio: 'inherit',
      stdio: 'pipe',
      ...options,
    })

    // 输出流仅支持管道 pipe，pipe 好像比 inherit 打包快60%左右,但是没有继承输出日志，长期打包对比试试验证
    // child.stdout.on("data", (chunk) => {
    //   process.stdout.write(chunk);
    // });

    // child.stderr.on("data", (chunk) => {
    //   process.stderr.write(chunk);
    // });

    child.on('close', (code) => {
      if (code === 0) {
        resolve()
      }
      else {
        reject(new Error(`${command} ${args.join(' ')} 退出码 ${code}`))
      }
    })
  })
}

async function onBuild() {
  console.log('🛠️ 开始构建...')
  await runCommand(buildCommandArgs, { cwd: LOCAL_PROJECT_PATH })
  console.log('\x1B[32m%s\x1B[0m', '✅ 构建完成')
}

async function onUpload() {
  console.log(`📤 开始上传...`)

  // 确保远程目录存在
  const mkdirCommandArgs = ['ssh', sshPath, '-p', `${REMOTE.port}`, `mkdir -p ${REMOTE.path}`]
  await runCommand(mkdirCommandArgs)

  const uploadPromises = FILES_TO_UPLOAD.map(async (item) => {
    const sourcePath = path.join(LOCAL_PROJECT_PATH, item)
    const targetPath = `${sshPath}:${REMOTE.path}/`
    console.log(`📂 文件 ${item} -> ${targetPath}`)
    // await execPromise(`rsync -avz --delete ${sourcePath} ${targetPath}`);
    const scpCommandArgs = ['scp', '-P', `${REMOTE.port}`, '-r', sourcePath, targetPath]
    await runCommand(scpCommandArgs)
  })

  await Promise.all(uploadPromises)
  console.log('\x1B[32m%s\x1B[0m', '✅ 上传完成')
}

async function onReload() {
  console.log('📦 开始部署...')

  const remoteCommands = [
    'source ~/.zshrc || true', // 加载 zsh 配置（即使文件不存在也继续），ssh 交互不会加载环境变量
    'nvm use 20',
    `mkdir -p ${REMOTE.path}`,
    `cd ${REMOTE.path}`,
    // `pnpm install --prod`,
    `pm2 list | grep -q '${PM2_APP_NAME}' && pm2 restart '${PM2_APP_NAME}' || pm2 start dist/src/main.js --name '${PM2_APP_NAME}' --max-restarts 5`,
  ].join(' && ')

  const sshCommandArgs = ['ssh', sshPath, '-p', `${REMOTE.port}`, remoteCommands]
  await runCommand(sshCommandArgs)

  console.log('\x1B[32m%s\x1B[0m', '✅ 部署完成')
}

(async () => {
  try {
    const startTime = Date.now()

    await onBuild()
    await onUpload()
    await onReload()

    const endTime = Date.now()

    console.log(new Date().toLocaleString('zh-cn'))
    console.log(`🚀 部署耗时: ${((endTime - startTime) / 1000).toFixed(2)}s`)

    process.exit(0)
  }
  catch (err) {
    console.error('❌ 出错啦：', err)
    process.exit(1)
  }
})()
